package com.btl.boot.core.config;

import cn.hutool.core.util.ArrayUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.Executor;

/**
 * 异步调用配置
 */
@Slf4j
@EnableAsync(proxyTargetClass = true)
@Configuration
@AutoConfigureBefore(JacksonAutoConfiguration.class)
public class AsyncConfiguration implements AsyncConfigurer {

    private final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() + 1;

    /**
     * 执行周期性或定时任务
     */
    @Bean
    public ThreadPoolTaskExecutor asyncPoolTaskExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
        threadPoolTaskExecutor.setMaxPoolSize(CORE_POOL_SIZE + 16);
        threadPoolTaskExecutor.setQueueCapacity(100);
        threadPoolTaskExecutor.setThreadNamePrefix("Async-pool-");
        threadPoolTaskExecutor.setTaskDecorator(runnable -> {
            Map<String, String> map = MDC.getCopyOfContextMap();
            return () -> {
                try {
                    MDC.setContextMap(map);
                    runnable.run();
                } finally {
                    MDC.clear();
                }
            };
        });
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }

    /**
     * 自定义 @Async 注解使用系统线程池
     */
    @NonNull
    @Override
    public Executor getAsyncExecutor() {
        return asyncPoolTaskExecutor();
    }

    /**
     * 异步执行异常处理
     */
    @NonNull
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (throwable, method, objects) -> {
            StringBuilder sb = new StringBuilder();
            sb.append("Exception message - ").append(throwable.getMessage())
                    .append(",Method name - ").append(method.getName());
            if (ArrayUtil.isNotEmpty(objects)) {
                sb.append(",Parameter value - ").append(Arrays.toString(objects));
            }
            log.error("Async-线程异常:{}", sb, throwable);
        };
    }

}
